﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using RemoteCode.Attributes;
using SecureConnection.Utils;


namespace RemoteCode
{
    internal class LocalClass
    {
        public LocalClass()
        {
        }

        public static Result Create(ref ByteArrayReader br, Nexum host)
        {
            string className = null;
            object[] parameters = null;
            try
            {
                className = br.ReadString();
                parameters = SerializationHelper.DeserializeArray(ref br);
            }
            catch (Exception ex) { return new Result(true, ex, NexumError.PacketParsingError, null); }

            Type classType = null;
            lock (host.LocalClasses)
            {
                if (!host.ClassesAllowedToShare.ContainsKey(className))
                    return new Result(true, null, NexumError.NotShared, null);

                classType = host.ClassesAllowedToShare[className];
            }


            LocalClass l = new LocalClass();

            ConstructorInfo ctorinfo = null;
            try
            {
                ctorinfo = InvokeHelper.FindConstructor(classType, parameters);
            }
            catch (Exception ex)
            {
                return new Result(true, ex, NexumError.ConstructorNotFound, null);
            }

            try
            {
                l.classObject = ctorinfo.Invoke(parameters);
            }
            catch (Exception ex)
            {
                return new Result(true, ex, NexumError.InvokeError, null);
            }

            l.id = host.generator.Generate(host.LocalClasses.Keys);
            l.type = classType;
            
            lock (host.LocalClasses)
            {
                host.LocalClasses.Add(l.id, l);
            }

            return new Result(false, null, NexumError.Success, l.id);
        }
        public static Result Dispose(ref ByteArrayReader br, Nexum host)
        {
            int id = 0;
            try
            {
                id = br.ReadInt();
            }
            catch (Exception ex) { return new Result(true, ex, NexumError.PacketParsingError, null); }

            lock (host.LocalClasses)
            {
                if (!host.LocalClasses.ContainsKey(id))
                    return new Result(true, null, NexumError.ClassNotFound, null);

                host.LocalClasses[id].classObject = null;
                host.LocalClasses[id].id = 0;

                host.LocalClasses.Remove(id);
            }

            return new Result(false, null, NexumError.Success, null);
        }            
        public static Result Invoke(ref ByteArrayReader br, Nexum host)
        {
            int id = 0;
            string methodName = null;
            object[] parameters = null;
            bool pointer = false;

            try
            {
                pointer = br.ReadByte() == 1;
                id = br.ReadInt();

                methodName = br.ReadString();
                parameters = SerializationHelper.DeserializeArray(ref br);
            }
            catch (Exception ex) { return new Result(true, ex, NexumError.PacketParsingError, null); }

            LocalClass l = null;
            lock (host.LocalClasses)
            {
                if (!host.LocalClasses.ContainsKey(id))
                    return new Result(true, null, NexumError.ClassNotFound, null);

                l = host.LocalClasses[id];
            }

            return InvokeHelper.InvokeMethod(l.type, methodName, parameters, l.classObject, pointer, host);
        }

        public int id;
        public object classObject;
        public Type type;
    }
}
